#include <event2/event.h>
#include <signal.h>
#include <assert.h>
#include <string.h>

#define SPORT 9005
void client_cb(evutil_socket_t clientfd, short w, void *arg)
{
    event *ev = (event*)arg;
    /* timeout */
    if(w & EV_TIMEOUT){
        event_free(ev);
        evutil_closesocket(clientfd);
        printf("timeout free\r\n");
        return;
    }
    char buf[1024] = {0};
    int len = recv(clientfd, buf, sizeof(buf)-1, 0);
    if(len>0){
        printf("client data:%s\r\n",buf);
        send(clientfd, "ok", 2, 0);
    } else {
        event_free(ev);
        evutil_closesocket(clientfd);
        printf("close free\r\n");
    }  
}
void listen_cb(evutil_socket_t listenfd, short w, void *arg)
{
    //printf("short-%d\r\n",w);
    //printf("socket_t-%d\r\n",listenfd);
    sockaddr_in sin;
    socklen_t size = sizeof(sin);
    /* accept */
    evutil_socket_t client = accept(listenfd, (sockaddr*)&sin, &size);
    char ip[16] = {0};
    evutil_inet_ntop(AF_INET, &sin.sin_addr, ip, sizeof(ip)-1);
    printf("ip addr is:%s\r\n",ip);

    /* read data */
    event_base *base = (event_base*)arg;
    event *ev = event_new(base, client, EV_READ|EV_PERSIST|EV_ET, client_cb, event_self_cbarg());
    timeval t = {10, 0};
    event_add(ev, &t);
}
int main() {
    /* ignore pipe signal */
    if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)
    {
        return 1;
    }
    event_base *base = event_base_new();
    
    /* create socket */
    evutil_socket_t listenfd = socket(AF_INET, SOCK_STREAM, 0);
    assert(listenfd > 0);
    //printf("socket_t-%d\r\n",listenfd);

    /* set reuse and noblocking */
    evutil_make_listen_socket_reuseable(listenfd);
    evutil_make_socket_nonblocking(listenfd);

    /* create sockaddr */
    sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SPORT);
    
    /* bind */
    int ret = ::bind(listenfd, (sockaddr*)&sin, sizeof(sin));
    assert( ret == 0 );

    /* listen */
    ret = ::listen(listenfd, 10);
    assert( ret ==0 );

    event *listenev = event_new(base, listenfd, EV_READ|EV_PERSIST, listen_cb, base);

    ret = event_add(listenev, 0);
    assert(ret == 0);

    event_base_dispatch(base);

    event_base_free(base);

    return 1;

}